React์ ์คํ์ ์ธ experimental_useOptimistic ํ ์ ์ดํด๋ณด๊ณ ๋์ ์ ๋ฐ์ดํธ๋ก ์ธํด ๋ฐ์ํ๋ ๊ฒฝ์ ์ํ๋ฅผ ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ๋ฐฐ์๋ณด์ธ์. ๋ฐ์ดํฐ ์ผ๊ด์ฑ๊ณผ ์ํํ ์ฌ์ฉ์ ๊ฒฝํ์ ๋ณด์ฅํ๊ธฐ ์ํ ์ ๋ต์ ์ดํดํฉ๋๋ค.
React experimental_useOptimistic ๊ฒฝ์ ์ํ: ๋์ ์ ๋ฐ์ดํธ ์ฒ๋ฆฌ
React์ experimental_useOptimistic ํ
์ ๋น๋๊ธฐ ์์
์ด ์งํ๋๋ ๋์ ์ฆ๊ฐ์ ์ธ ํผ๋๋ฐฑ์ ์ ๊ณตํ์ฌ ์ฌ์ฉ์ ๊ฒฝํ์ ๊ฐ์ ํ๋ ๊ฐ๋ ฅํ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค. ๊ทธ๋ฌ๋ ์ด๋ฌํ ๋๊ด์ฃผ์๋ ์ฌ๋ฌ ์
๋ฐ์ดํธ๊ฐ ๋์์ ์ ์ฉ๋ ๋ ๋๋๋ก ๊ฒฝ์ ์ํ๋ก ์ด์ด์ง ์ ์์ต๋๋ค. ์ด ๊ธ์์๋ ์ด ๋ฌธ์ ์ ๋ณต์ก์ฑ์ ๊น์ด ํ๊ณ ๋ค์ด ๋์ ์
๋ฐ์ดํธ๋ฅผ ๊ฒฌ๊ณ ํ๊ฒ ์ฒ๋ฆฌํ๊ณ , ๋ฐ์ดํฐ ์ผ๊ด์ฑ๊ณผ ์ํํ ์ฌ์ฉ์ ๊ฒฝํ์ ๋ณด์ฅํ๋ฉฐ, ์ ์ธ๊ณ ์ฌ์ฉ์๋ฅผ ๋ง์กฑ์ํค๋ ์ ๋ต์ ์ ๊ณตํฉ๋๋ค.
experimental_useOptimistic ์ดํดํ๊ธฐ
๊ฒฝ์ ์ํ์ ๋ํด ์์๋ณด๊ธฐ ์ ์, experimental_useOptimistic์ด ์ด๋ป๊ฒ ์๋ํ๋์ง ๊ฐ๋จํ ์์ฝํด ๋ณด๊ฒ ์ต๋๋ค. ์ด ํ
์ ์ฌ์ฉํ๋ฉด ํด๋น ์๋ฒ ์ธก ์์
์ด ์๋ฃ๋๊ธฐ ์ ์ ๊ฐ์ ์ฌ์ฉํ์ฌ UI๋ฅผ ๋๊ด์ ์ผ๋ก ์
๋ฐ์ดํธํ ์ ์์ต๋๋ค. ์ด๋ ์ฌ์ฉ์์๊ฒ ์ฆ๊ฐ์ ์ธ ํ๋์ด๋ผ๋ ์ธ์์ ์ฃผ์ด ์๋ต์ฑ์ ํฅ์์ํต๋๋ค. ์๋ฅผ ๋ค์ด, ์ฌ์ฉ์๊ฐ ๊ฒ์๋ฌผ์ '์ข์์'๋ฅผ ๋๋ฅด๋ ๊ฒฝ์ฐ๋ฅผ ์๊ฐํด ๋ณด์ธ์. ์๋ฒ๊ฐ '์ข์์'๋ฅผ ํ์ธํ ๋๊น์ง ๊ธฐ๋ค๋ฆฌ๋ ๋์ , ์ฆ์ UI๋ฅผ ์
๋ฐ์ดํธํ์ฌ ๊ฒ์๋ฌผ์ด '์ข์์'๋ฅผ ๋ฐ์ ๊ฒ์ผ๋ก ํ์ํ๊ณ , ์๋ฒ์์ ์ค๋ฅ๋ฅผ ๋ณด๊ณ ํ๋ฉด ๋๋๋ฆด ์ ์์ต๋๋ค.
๊ธฐ๋ณธ์ ์ธ ์ฌ์ฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
const [optimisticValue, addOptimisticValue] = experimental_useOptimistic(
originalValue,
(currentState, newValue) => {
// Return the optimistic update based on the current state and new value
return newValue;
}
);
originalValue๋ ์ด๊ธฐ ์ํ์
๋๋ค. ๋ ๋ฒ์งธ ์ธ์๋ ๋๊ด์ ์
๋ฐ์ดํธ ํจ์๋ก, ํ์ฌ ์ํ์ ์ ๊ฐ์ ๋ฐ์ ๋๊ด์ ์ผ๋ก ์
๋ฐ์ดํธ๋ ์ํ๋ฅผ ๋ฐํํฉ๋๋ค. addOptimisticValue๋ ๋๊ด์ ์
๋ฐ์ดํธ๋ฅผ ํธ๋ฆฌ๊ฑฐํ๊ธฐ ์ํด ํธ์ถํ ์ ์๋ ํจ์์
๋๋ค.
๊ฒฝ์ ์ํ๋ ๋ฌด์์ธ๊ฐ?
๊ฒฝ์ ์ํ๋ ์ฌ๋ฌ ํ๋ก์ธ์ค๋ ์ค๋ ๋์ ์์ธก ๋ถ๊ฐ๋ฅํ ์์๋ ํ์ด๋ฐ์ ํ๋ก๊ทธ๋จ์ ๊ฒฐ๊ณผ๊ฐ ์์กดํ ๋ ๋ฐ์ํฉ๋๋ค. experimental_useOptimistic์ ๋งฅ๋ฝ์์ ๊ฒฝ์ ์ํ๋ ์ฌ๋ฌ ๋๊ด์ ์
๋ฐ์ดํธ๊ฐ ๋์์ ํธ๋ฆฌ๊ฑฐ๋๊ณ , ํด๋น ์๋ฒ ์ธก ์์
์ด ์์๋ ์์์ ๋ค๋ฅธ ์์๋ก ์๋ฃ๋ ๋ ๋ฐ์ํฉ๋๋ค. ์ด๋ ์ผ๊ด์ฑ ์๋ ๋ฐ์ดํฐ์ ํผ๋์ค๋ฌ์ด ์ฌ์ฉ์ ๊ฒฝํ์ผ๋ก ์ด์ด์ง ์ ์์ต๋๋ค.
์ฌ์ฉ์๊ฐ '์ข์์' ๋ฒํผ์ ๋น ๋ฅด๊ฒ ์ฌ๋ฌ ๋ฒ ํด๋ฆญํ๋ ์๋๋ฆฌ์ค๋ฅผ ์๊ฐํด ๋ณด์ธ์. ๊ฐ ํด๋ฆญ์ ๋๊ด์ ์ ๋ฐ์ดํธ๋ฅผ ํธ๋ฆฌ๊ฑฐํ์ฌ UI์ ์ข์์ ์๋ฅผ ์ฆ์ ์ฆ๊ฐ์ํต๋๋ค. ๊ทธ๋ฌ๋ ๊ฐ '์ข์์'์ ๋ํ ์๋ฒ ์์ฒญ์ ๋คํธ์ํฌ ์ง์ฐ ์๊ฐ์ด๋ ์๋ฒ ์ฒ๋ฆฌ ์ง์ฐ์ผ๋ก ์ธํด ๋ค๋ฅธ ์์๋ก ์๋ฃ๋ ์ ์์ต๋๋ค. ๋ง์ฝ ์์ฒญ์ด ์์ ์์ด ์๋ฃ๋๋ฉด, ์ฌ์ฉ์์๊ฒ ํ์๋๋ ์ต์ข ์ข์์ ์๊ฐ ๋ถ์ ํํ ์ ์์ต๋๋ค.
์์: ์นด์ดํฐ๊ฐ 0์์ ์์ํ๋ค๊ณ ์์ํด ๋ณด์ธ์. ์ฌ์ฉ์๊ฐ ์ฆ๊ฐ ๋ฒํผ์ ๋น ๋ฅด๊ฒ ๋ ๋ฒ ํด๋ฆญํฉ๋๋ค. ๋ ๊ฐ์ ๋๊ด์ ์ ๋ฐ์ดํธ๊ฐ ์ ๋ฌ๋ฉ๋๋ค. ์ฒซ ๋ฒ์งธ ์ ๋ฐ์ดํธ๋ `0 + 1 = 1`์ด๊ณ , ๋ ๋ฒ์งธ๋ `1 + 1 = 2`์ ๋๋ค. ๊ทธ๋ฌ๋ ๋ง์ฝ ๋ ๋ฒ์งธ ํด๋ฆญ์ ๋ํ ์๋ฒ ์์ฒญ์ด ๋จผ์ ์๋ฃ๋๋ฉด, ์๋ฒ๋ ์ค๋๋ ๊ฐ์ ๊ธฐ๋ฐ์ผ๋ก ์ํ๋ฅผ `0 + 1 = 1`๋ก ์๋ชป ์ ์ฅํ ์ ์์ผ๋ฉฐ, ๊ทธ ํ ์ฒซ ๋ฒ์งธ๋ก ์๋ฃ๋ ์์ฒญ์ด ๋ค์ `0 + 1 = 1`๋ก ๋ฎ์ด์ธ ์ ์์ต๋๋ค. ์ฌ์ฉ์๋ ๊ฒฐ๊ตญ `1`์ ๋ณด๊ฒ ๋๊ณ , `2`๊ฐ ์๋๋๋ค.
experimental_useOptimistic์ผ๋ก ๊ฒฝ์ ์ํ ์๋ณํ๊ธฐ
๊ฒฝ์ ์ํ๋ฅผ ์๋ณํ๋ ๊ฒ์ ์ข ์ข ๊ฐํ์ ์ด๊ณ ํ์ด๋ฐ ์์์ ์์กดํ๊ธฐ ๋๋ฌธ์ ์ด๋ ค์ธ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ๋ช ๊ฐ์ง ์ผ๋ฐ์ ์ธ ์ฆ์์ ๊ทธ ์กด์ฌ๋ฅผ ๋ํ๋ผ ์ ์์ต๋๋ค:
- ์ผ๊ด์ฑ ์๋ UI ์ํ: UI๊ฐ ์ค์ ์๋ฒ ์ธก ๋ฐ์ดํฐ๋ฅผ ๋ฐ์ํ์ง ์๋ ๊ฐ์ ํ์ํฉ๋๋ค.
- ์์์น ๋ชปํ ๋ฐ์ดํฐ ๋ฎ์ด์ฐ๊ธฐ: ๋ฐ์ดํฐ๊ฐ ์ค๋๋ ๊ฐ์ผ๋ก ๋ฎ์ด์์์ ธ ๋ฐ์ดํฐ ์์ค๋ก ์ด์ด์ง๋๋ค.
- ๊น๋นก์ด๋ UI ์์: ๋ค๋ฅธ ๋๊ด์ ์ ๋ฐ์ดํธ๊ฐ ์ ์ฉ๋๊ณ ๋๋๋ ค์ง๋ฉด์ UI ์์๊ฐ ๊น๋นก์ด๊ฑฐ๋ ๋น ๋ฅด๊ฒ ๋ณ๊ฒฝ๋ฉ๋๋ค.
๊ฒฝ์ ์ํ๋ฅผ ํจ๊ณผ์ ์ผ๋ก ์๋ณํ๋ ค๋ฉด ๋ค์์ ๊ณ ๋ คํ์ญ์์ค:
- ๋ก๊น : ๋๊ด์ ์ ๋ฐ์ดํธ๊ฐ ํธ๋ฆฌ๊ฑฐ๋๋ ์์์ ํด๋น ์๋ฒ ์ธก ์์ ์ด ์๋ฃ๋๋ ์์๋ฅผ ์ถ์ ํ๊ธฐ ์ํด ์์ธํ ๋ก๊น ์ ๊ตฌํํ์ญ์์ค. ๊ฐ ์ ๋ฐ์ดํธ์ ๋ํ ํ์์คํฌํ์ ๊ณ ์ ์๋ณ์๋ฅผ ํฌํจํ์ญ์์ค.
- ํ ์คํธ: ๋์ ์ ๋ฐ์ดํธ๋ฅผ ์๋ฎฌ๋ ์ด์ ํ๊ณ UI ์ํ๊ฐ ์ผ๊ด์ฑ์ ์ ์งํ๋์ง ํ์ธํ๋ ํตํฉ ํ ์คํธ๋ฅผ ์์ฑํ์ญ์์ค. Jest๋ React Testing Library์ ๊ฐ์ ๋๊ตฌ๊ฐ ์ด์ ์ ์ฉํ ์ ์์ต๋๋ค. ๋ค์ํ ๋คํธ์ํฌ ์ง์ฐ ์๊ฐ๊ณผ ์๋ฒ ์๋ต ์๊ฐ์ ์๋ฎฌ๋ ์ด์ ํ๊ธฐ ์ํด ๋ชจํน ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉ์ ๊ณ ๋ คํ์ญ์์ค.
- ๋ชจ๋ํฐ๋ง: ์ด์ ํ๊ฒฝ์์ UI ๋ถ์ผ์น ๋ฐ ๋ฐ์ดํฐ ๋ฎ์ด์ฐ๊ธฐ ๋น๋๋ฅผ ์ถ์ ํ๊ธฐ ์ํ ๋ชจ๋ํฐ๋ง ๋๊ตฌ๋ฅผ ๊ตฌํํ์ญ์์ค. ์ด๋ ๊ฐ๋ฐ ์ค์๋ ๋ช ํํ์ง ์์ ์ ์๋ ์ ์ฌ์ ์ธ ๊ฒฝ์ ์ํ๋ฅผ ์๋ณํ๋ ๋ฐ ๋์์ด ๋ ์ ์์ต๋๋ค.
- ์ฌ์ฉ์ ํผ๋๋ฐฑ: UI ๋ถ์ผ์น๋ ๋ฐ์ดํฐ ์์ค์ ๋ํ ์ฌ์ฉ์ ๋ณด๊ณ ์ ์ธ์ฌํ ์ฃผ์๋ฅผ ๊ธฐ์ธ์ด์ญ์์ค. ์ฌ์ฉ์ ํผ๋๋ฐฑ์ ์๋ํ๋ ํ ์คํธ๋ฅผ ํตํด ๊ฐ์งํ๊ธฐ ์ด๋ ค์ด ์ ์ฌ์ ์ธ ๊ฒฝ์ ์ํ์ ๋ํ ๊ท์คํ ํต์ฐฐ๋ ฅ์ ์ ๊ณตํ ์ ์์ต๋๋ค.
๋์ ์ ๋ฐ์ดํธ ์ฒ๋ฆฌ ์ ๋ต
experimental_useOptimistic์ ์ฌ์ฉํ ๋ ๊ฒฝ์ ์ํ๋ฅผ ์ํํ๊ธฐ ์ํด ์ฌ๋ฌ ์ ๋ต์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๋ค์์ ๊ฐ์ฅ ํจ๊ณผ์ ์ธ ์ ๊ทผ ๋ฐฉ์ ์ค ์ผ๋ถ์
๋๋ค:
1. ๋๋ฐ์ด์ฑ๊ณผ ์ค๋กํ๋ง
๋๋ฐ์ด์ฑ(Debouncing)์ ํจ์๊ฐ ์คํ๋ ์ ์๋ ๋น๋๋ฅผ ์ ํํฉ๋๋ค. ํจ์๊ฐ ๋ง์ง๋ง์ผ๋ก ํธ์ถ๋ ํ ์ผ์ ์๊ฐ์ด ์ง๋ ๋๊น์ง ํจ์ ํธ์ถ์ ์ง์ฐ์ํต๋๋ค. ๋๊ด์ ์ ๋ฐ์ดํธ์ ๋งฅ๋ฝ์์ ๋๋ฐ์ด์ฑ์ ๋น ๋ฅด๊ณ ์ฐ์์ ์ธ ์ ๋ฐ์ดํธ๊ฐ ํธ๋ฆฌ๊ฑฐ๋๋ ๊ฒ์ ๋ฐฉ์งํ์ฌ ๊ฒฝ์ ์ํ์ ๊ฐ๋ฅ์ฑ์ ์ค์ผ ์ ์์ต๋๋ค.
์ค๋กํ๋ง(Throttling)์ ํจ์๊ฐ ์ง์ ๋ ๊ธฐ๊ฐ ๋ด์ ์ต๋ ํ ๋ฒ๋ง ํธ์ถ๋๋๋ก ๋ณด์ฅํฉ๋๋ค. ์ด๋ ํจ์ ํธ์ถ์ ๋น๋๋ฅผ ์กฐ์ ํ์ฌ ์์คํ ์ ๊ณผ๋ถํ๊ฐ ๊ฑธ๋ฆฌ๋ ๊ฒ์ ๋ฐฉ์งํฉ๋๋ค. ์ค๋กํ๋ง์ ์ ๋ฐ์ดํธ๊ฐ ๋ฐ์ํ๋๋ก ํ์ฉํ๋, ์ ์ด๋ ์๋๋ก ์ด๋ฃจ์ด์ง๊ธฐ๋ฅผ ์ํ ๋ ์ ์ฉํฉ๋๋ค.
๋ค์์ ๋๋ฐ์ด์ค๋ ํจ์๋ฅผ ์ฌ์ฉํ๋ ์์์ ๋๋ค:
import { useCallback } from 'react';
import { debounce } from 'lodash'; // Or a custom debounce function
function MyComponent() {
const handleClick = useCallback(
debounce(() => {
addOptimisticValue(currentState => currentState + 1);
// Send request to server here
}, 300), // Debounce for 300ms
[addOptimisticValue]
);
return ;
}
2. ์ํ์ค ๋ฒํธ ์ง์
๊ฐ ๋๊ด์ ์ ๋ฐ์ดํธ์ ๊ณ ์ ํ ์ํ์ค ๋ฒํธ๋ฅผ ํ ๋นํ์ญ์์ค. ์๋ฒ๊ฐ ์๋ตํ ๋, ์๋ต์ด ์ต์ ์ํ์ค ๋ฒํธ์ ํด๋นํ๋์ง ํ์ธํ์ญ์์ค. ์๋ต์ด ์์์ ๋ง์ง ์์ผ๋ฉด ํ๊ธฐํ์ญ์์ค. ์ด๋ ๊ฒ ํ๋ฉด ๊ฐ์ฅ ์ต๊ทผ์ ์ ๋ฐ์ดํธ๋ง ์ ์ฉ๋๋๋ก ๋ณด์ฅํฉ๋๋ค.
๋ค์์ ์ํ์ค ๋ฒํธ๋ฅผ ๊ตฌํํ๋ ๋ฐฉ๋ฒ์ ๋๋ค:
import { useRef, useCallback, useState } from 'react';
function MyComponent() {
const [value, setValue] = useState(0);
const [optimisticValue, addOptimisticValue] = experimental_useOptimistic(value, (state, newValue) => newValue);
const sequenceNumber = useRef(0);
const handleIncrement = useCallback(() => {
const currentSequenceNumber = ++sequenceNumber.current;
addOptimisticValue(value + 1);
// Simulate a server request
simulateServerRequest(value + 1, currentSequenceNumber)
.then((data) => {
if (data.sequenceNumber === sequenceNumber.current) {
setValue(data.value);
} else {
console.log("Discarding outdated response");
}
});
}, [value, addOptimisticValue]);
async function simulateServerRequest(newValue, sequenceNumber) {
// Simulate network latency
await new Promise(resolve => setTimeout(resolve, Math.random() * 500));
return { value: newValue, sequenceNumber: sequenceNumber };
}
return (
Value: {optimisticValue}
);
}
์ด ์์์์ ๊ฐ ์ ๋ฐ์ดํธ์๋ ์ํ์ค ๋ฒํธ๊ฐ ํ ๋น๋ฉ๋๋ค. ์๋ฒ ์๋ต์๋ ํด๋น ์์ฒญ์ ์ํ์ค ๋ฒํธ๊ฐ ํฌํจ๋ฉ๋๋ค. ์๋ต์ ๋ฐ์ผ๋ฉด ์ปดํฌ๋ํธ๋ ์ํ์ค ๋ฒํธ๊ฐ ํ์ฌ ์ํ์ค ๋ฒํธ์ ์ผ์นํ๋์ง ํ์ธํฉ๋๋ค. ์ผ์นํ๋ฉด ์ ๋ฐ์ดํธ๊ฐ ์ ์ฉ๋ฉ๋๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด ์ ๋ฐ์ดํธ๋ ํ๊ธฐ๋ฉ๋๋ค.
3. ์ ๋ฐ์ดํธ๋ฅผ ์ํ ํ ์ฌ์ฉ
๋ณด๋ฅ ์ค์ธ ์ ๋ฐ์ดํธ ํ๋ฅผ ์ ์งํ์ญ์์ค. ์ ๋ฐ์ดํธ๊ฐ ํธ๋ฆฌ๊ฑฐ๋๋ฉด ํ์ ์ถ๊ฐํ์ญ์์ค. ํ์์ ์ ๋ฐ์ดํธ๋ฅผ ์์ฐจ์ ์ผ๋ก ์ฒ๋ฆฌํ์ฌ ์์๋ ์์๋๋ก ์ ์ฉ๋๋๋ก ๋ณด์ฅํฉ๋๋ค. ์ด๋ ์์๊ฐ ๋ค๋ฐ๋ ์ ๋ฐ์ดํธ์ ๊ฐ๋ฅ์ฑ์ ์ ๊ฑฐํฉ๋๋ค.
๋ค์์ ์ ๋ฐ์ดํธ์ ํ๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ์์์ ๋๋ค:
import { useState, useCallback, useRef, useEffect } from 'react';
function MyComponent() {
const [value, setValue] = useState(0);
const [optimisticValue, addOptimisticValue] = experimental_useOptimistic(value, (state, newValue) => newValue);
const updateQueue = useRef([]);
const isProcessing = useRef(false);
const processQueue = useCallback(async () => {
if (isProcessing.current || updateQueue.current.length === 0) {
return;
}
isProcessing.current = true;
const nextUpdate = updateQueue.current.shift();
const newValue = nextUpdate();
try {
// Simulate a server request
const result = await simulateServerRequest(newValue);
setValue(result);
} finally {
isProcessing.current = false;
processQueue(); // Process the next item in the queue
}
}, [setValue]);
useEffect(() => {
processQueue();
}, [processQueue]);
const handleIncrement = useCallback(() => {
addOptimisticValue(value + 1);
updateQueue.current.push(() => value + 1);
processQueue();
}, [value, addOptimisticValue, processQueue]);
async function simulateServerRequest(newValue) {
// Simulate network latency
await new Promise(resolve => setTimeout(resolve, Math.random() * 500));
return newValue;
}
return (
Value: {optimisticValue}
);
}
์ด ์์์์๋ ๊ฐ ์
๋ฐ์ดํธ๊ฐ ํ์ ์ถ๊ฐ๋ฉ๋๋ค. processQueue ํจ์๋ ํ์์ ์์ฐจ์ ์ผ๋ก ์
๋ฐ์ดํธ๋ฅผ ์ฒ๋ฆฌํฉ๋๋ค. isProcessing ref๋ ์ฌ๋ฌ ์
๋ฐ์ดํธ๊ฐ ๋์์ ์ฒ๋ฆฌ๋๋ ๊ฒ์ ๋ฐฉ์งํฉ๋๋ค.
4. ๋ฉฑ๋ฑ์ฑ ์์
์๋ฒ ์ธก ์์ ์ด ๋ฉฑ๋ฑ์ฑ(idempotent)์ ๊ฐ๋๋ก ํ์ญ์์ค. ๋ฉฑ๋ฑ์ฑ ์์ ์ ์ด๊ธฐ ์ ์ฉ ์ดํ์๋ ์ฌ๋ฌ ๋ฒ ์ ์ฉํด๋ ๊ฒฐ๊ณผ๊ฐ ๋ฐ๋์ง ์๋ ์์ ์ ๋๋ค. ์๋ฅผ ๋ค์ด, ๊ฐ์ ์ค์ ํ๋ ๊ฒ์ ๋ฉฑ๋ฑ์ฑ์ด์ง๋ง, ๊ฐ์ ์ฆ๊ฐ์ํค๋ ๊ฒ์ ๊ทธ๋ ์ง ์์ต๋๋ค.
์์ ์ด ๋ฉฑ๋ฑ์ฑ์ ๊ฐ๋๋ค๋ฉด ๊ฒฝ์ ์ํ๋ ๋ ์ฐ๋ ค๋ฉ๋๋ค. ์ ๋ฐ์ดํธ๊ฐ ์์ ์์ด ์ ์ฉ๋๋๋ผ๋ ์ต์ข ๊ฒฐ๊ณผ๋ ๋์ผํ ๊ฒ์ ๋๋ค. ์ฆ๊ฐ ์์ ์ ๋ฉฑ๋ฑ์ฑ ์๊ฒ ๋ง๋ค๋ ค๋ฉด, ์ฆ๊ฐ ๋ช ๋ น ๋์ ์ํ๋ ์ต์ข ๊ฐ์ ์๋ฒ์ ๋ณด๋ผ ์ ์์ต๋๋ค.
์์: "์ข์์ ์ ์ฆ๊ฐ" ์์ฒญ์ ๋ณด๋ด๋ ๋์ , "์ข์์ ์๋ฅผ X๋ก ์ค์ "ํ๋ ์์ฒญ์ ๋ณด๋ด์ญ์์ค. ์๋ฒ๊ฐ ์ฌ๋ฌ ๊ฐ์ ๊ทธ๋ฌํ ์์ฒญ์ ๋ฐ๋๋ผ๋, ์์ฒญ์ด ์ฒ๋ฆฌ๋๋ ์์์ ๊ด๊ณ์์ด ์ต์ข ์ข์์ ์๋ ํญ์ X๊ฐ ๋ ๊ฒ์ ๋๋ค.
5. ๋กค๋ฐฑ์ ํฌํจํ ๋๊ด์ ํธ๋์ญ์
๋กค๋ฐฑ ๋ฉ์ปค๋์ฆ์ ํฌํจํ๋ ๋๊ด์ ํธ๋์ญ์ ์ ๊ตฌํํ์ญ์์ค. ๋๊ด์ ์ ๋ฐ์ดํธ๊ฐ ์ ์ฉ๋ ๋ ์๋ ๊ฐ์ ์ ์ฅํ์ญ์์ค. ์๋ฒ์์ ์ค๋ฅ๋ฅผ ๋ณด๊ณ ํ๋ฉด ์๋ ๊ฐ์ผ๋ก ๋๋๋ฆฌ์ญ์์ค. ์ด๋ ๊ฒ ํ๋ฉด UI ์ํ๊ฐ ์๋ฒ ์ธก ๋ฐ์ดํฐ์ ์ผ๊ด์ฑ์ ์ ์งํ๋๋ก ๋ณด์ฅํฉ๋๋ค.
๋ค์์ ๊ฐ๋ ์ ์ธ ์์์ ๋๋ค:
import { useState, useCallback } from 'react';
function MyComponent() {
const [value, setValue] = useState(0);
const [optimisticValue, addOptimisticValue] = experimental_useOptimistic(value, (state, newValue) => newValue);
const [previousValue, setPreviousValue] = useState(value);
const handleIncrement = useCallback(() => {
setPreviousValue(value);
addOptimisticValue(value + 1);
simulateServerRequest(value + 1)
.then(newValue => {
setValue(newValue);
})
.catch(() => {
// Rollback
setValue(previousValue);
addOptimisticValue(previousValue); //Re-render with corrected value optimistically
});
}, [value, addOptimisticValue, previousValue]);
async function simulateServerRequest(newValue) {
// Simulate network latency
await new Promise(resolve => setTimeout(resolve, Math.random() * 500));
// Simulate potential error
if (Math.random() < 0.2) {
throw new Error("Server error");
}
return newValue;
}
return (
Value: {optimisticValue}
);
}
์ด ์์์์๋ ๋๊ด์ ์
๋ฐ์ดํธ๊ฐ ์ ์ฉ๋๊ธฐ ์ ์ ์๋ ๊ฐ์ด previousValue์ ์ ์ฅ๋ฉ๋๋ค. ์๋ฒ์์ ์ค๋ฅ๋ฅผ ๋ณด๊ณ ํ๋ฉด ์ปดํฌ๋ํธ๋ ์๋ ๊ฐ์ผ๋ก ๋๋์๊ฐ๋๋ค.
6. ๋ถ๋ณ์ฑ ์ฌ์ฉ
๋ถ๋ณ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ฅผ ์ฌ์ฉํ์ญ์์ค. ๋ถ๋ณ์ฑ์ ๋ฐ์ดํฐ๊ฐ ์ง์ ์์ ๋์ง ์๋๋ก ๋ณด์ฅํฉ๋๋ค. ๋์ ์ํ๋ ๋ณ๊ฒฝ ์ฌํญ์ด ์ ์ฉ๋ ๋ฐ์ดํฐ์ ์ ๋ณต์ฌ๋ณธ์ด ์์ฑ๋ฉ๋๋ค. ์ด๋ ๋ณ๊ฒฝ ์ฌํญ์ ์ถ์ ํ๊ณ ์ด์ ์ํ๋ก ๋๋๋ฆฌ๊ธฐ ์ฝ๊ฒ ๋ง๋ค์ด ๊ฒฝ์ ์ํ์ ์ํ์ ์ค์ ๋๋ค.
Immer๋ Immutable.js์ ๊ฐ์ JavaScript ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ๋ถ๋ณ ๋ฐ์ดํฐ ๊ตฌ์กฐ๋ฅผ ๋ค๋ฃจ๋ ๋ฐ ๋์์ด ๋ ์ ์์ต๋๋ค.
7. ๋ก์ปฌ ์ํ๋ฅผ ์ด์ฉํ ๋๊ด์ UI
experimental_useOptimistic์๋ง ์์กดํ๊ธฐ๋ณด๋ค๋ ๋ก์ปฌ ์ํ์์ ๋๊ด์ ์
๋ฐ์ดํธ๋ฅผ ๊ด๋ฆฌํ๋ ๊ฒ์ ๊ณ ๋ คํ์ญ์์ค. ์ด๋ ์
๋ฐ์ดํธ ํ๋ก์ธ์ค์ ๋ํ ๋ ๋ง์ ์ ์ด๊ถ์ ๋ถ์ฌํ๊ณ ๋์ ์
๋ฐ์ดํธ ์ฒ๋ฆฌ๋ฅผ ์ํ ์ฌ์ฉ์ ์ง์ ๋ก์ง์ ๊ตฌํํ ์ ์๊ฒ ํฉ๋๋ค. ๋ฐ์ดํฐ ์ผ๊ด์ฑ์ ๋ณด์ฅํ๊ธฐ ์ํด ์ํ์ค ๋ฒํธ ์ง์ ์ด๋ ํ์๊ณผ ๊ฐ์ ๊ธฐ์ ๊ณผ ๊ฒฐํฉํ ์ ์์ต๋๋ค.
8. ์ต์ข ์ ์ผ๊ด์ฑ
์ต์ข ์ ์ผ๊ด์ฑ์ ์์ฉํ์ญ์์ค. UI ์ํ๊ฐ ์ผ์์ ์ผ๋ก ์๋ฒ ์ธก ๋ฐ์ดํฐ์ ๋๊ธฐํ๋์ง ์์ ์ ์์์ ๋ฐ์๋ค์ด์ญ์์ค. ์ ํ๋ฆฌ์ผ์ด์ ์ด ์ด๋ฅผ ์ํํ๊ฒ ์ฒ๋ฆฌํ๋๋ก ์ค๊ณํ์ญ์์ค. ์๋ฅผ ๋ค์ด, ์๋ฒ๊ฐ ์ ๋ฐ์ดํธ๋ฅผ ์ฒ๋ฆฌํ๋ ๋์ ๋ก๋ฉ ํ์๊ธฐ๋ฅผ ํ์ํ์ญ์์ค. ๋ฐ์ดํฐ๊ฐ ๊ธฐ๊ธฐ ๊ฐ์ ์ฆ์ ์ผ๊ด๋์ง ์์ ์ ์์์ ์ฌ์ฉ์์๊ฒ ๊ต์กํ์ญ์์ค.
๊ธ๋ก๋ฒ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ํ ๋ชจ๋ฒ ์ฌ๋ก
๊ธ๋ก๋ฒ ์ฌ์ฉ์๋ฅผ ์ํ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ ๋๋ ๋คํธ์ํฌ ์ง์ฐ ์๊ฐ, ์๊ฐ๋, ์ธ์ด ํ์งํ์ ๊ฐ์ ์์๋ฅผ ๊ณ ๋ คํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค.
- ๋คํธ์ํฌ ์ง์ฐ ์๊ฐ: ๋ฐ์ดํฐ๋ฅผ ๋ก์ปฌ์ ์บ์ฑํ๊ณ ์ง๋ฆฌ์ ์ผ๋ก ๋ถ์ฐ๋ ์๋ฒ์์ ์ฝํ ์ธ ๋ฅผ ์ ๊ณตํ๊ธฐ ์ํด ์ฝํ ์ธ ์ ์ก ๋คํธ์ํฌ(CDN)๋ฅผ ์ฌ์ฉํ๋ ๋ฑ ๋คํธ์ํฌ ์ง์ฐ ์๊ฐ์ ์ํฅ์ ์ํํ๋ ์ ๋ต์ ๊ตฌํํ์ญ์์ค.
- ์๊ฐ๋: ๋ค๋ฅธ ์๊ฐ๋์ ์ฌ์ฉ์์๊ฒ ๋ฐ์ดํฐ๊ฐ ์ ํํ๊ฒ ํ์๋๋๋ก ์๊ฐ๋๋ฅผ ์ฌ๋ฐ๋ฅด๊ฒ ์ฒ๋ฆฌํ์ญ์์ค. ์ ๋ขฐํ ์ ์๋ ์๊ฐ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ฌ์ฉํ๊ณ Moment.js๋ date-fns์ ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ ์๊ฐ๋ ๋ณํ์ ๋จ์ํํ๋ ๊ฒ์ ๊ณ ๋ คํ์ญ์์ค.
- ํ์งํ: ์ฌ๋ฌ ์ธ์ด์ ์ง์ญ์ ์ง์ํ๋๋ก ์ ํ๋ฆฌ์ผ์ด์ ์ ํ์งํํ์ญ์์ค. i18next๋ React Intl๊ณผ ๊ฐ์ ํ์งํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ ๋ฒ์ญ์ ๊ด๋ฆฌํ๊ณ ์ฌ์ฉ์์ ๋ก์บ์ ๋ฐ๋ผ ๋ฐ์ดํฐ๋ฅผ ํ์ํํ์ญ์์ค.
- ์ ๊ทผ์ฑ: ์ฅ์ ๊ฐ ์๋ ์ฌ์ฉ์๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ ๊ทผํ ์ ์๋๋ก ํ์ญ์์ค. ๋ชจ๋ ์ฌ๋์ด ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฌ์ฉํ ์ ์๋๋ก WCAG์ ๊ฐ์ ์ ๊ทผ์ฑ ๊ฐ์ด๋๋ผ์ธ์ ๋ฐ๋ฅด์ญ์์ค.
๊ฒฐ๋ก
experimental_useOptimistic์ ์ฌ์ฉ์ ๊ฒฝํ์ ํฅ์์ํค๋ ๊ฐ๋ ฅํ ๋ฐฉ๋ฒ์ ์ ๊ณตํ์ง๋ง, ๊ฒฝ์ ์ํ์ ๊ฐ๋ฅ์ฑ์ ์ดํดํ๊ณ ํด๊ฒฐํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ์ด ๊ธ์์ ์ค๋ช
ํ ์ ๋ต์ ๊ตฌํํจ์ผ๋ก์จ, ๋์ ์
๋ฐ์ดํธ๋ฅผ ์ฒ๋ฆฌํ ๋์๋ ์ํํ๊ณ ์ผ๊ด๋ ์ฌ์ฉ์ ๊ฒฝํ์ ์ ๊ณตํ๋ ๊ฒฌ๊ณ ํ๊ณ ์ ๋ขฐํ ์ ์๋ ์ ํ๋ฆฌ์ผ์ด์
์ ๊ตฌ์ถํ ์ ์์ต๋๋ค. ์ ์ธ๊ณ ์ฌ์ฉ์์ ์๊ตฌ๋ฅผ ์ถฉ์กฑ์ํค๊ธฐ ์ํด ๋ฐ์ดํฐ ์ผ๊ด์ฑ, ์ค๋ฅ ์ฒ๋ฆฌ, ์ฌ์ฉ์ ํผ๋๋ฐฑ์ ์ฐ์ ์ํ๋ ๊ฒ์ ๊ธฐ์ตํ์ญ์์ค. ๋๊ด์ ์
๋ฐ์ดํธ์ ์ ์ฌ์ ๋ถ์ผ์น ์ฌ์ด์ ์ฅ๋จ์ ์ ์ ์คํ๊ฒ ๊ณ ๋ คํ๊ณ , ์ ํ๋ฆฌ์ผ์ด์
์ ํน์ ์๊ตฌ ์ฌํญ์ ๊ฐ์ฅ ์ ๋ง๋ ์ ๊ทผ ๋ฐฉ์์ ์ ํํ์ญ์์ค. ๋์ ์
๋ฐ์ดํธ๋ฅผ ๊ด๋ฆฌํ๋ ๋ฐ ์ฌ์ ์๋ฐฉ์ ์ ๊ทผ ๋ฐฉ์์ ์ทจํจ์ผ๋ก์จ, ๊ฒฝ์ ์ํ ๋ฐ ๋ฐ์ดํฐ ์์์ ์ํ์ ์ต์ํํ๋ฉด์ experimental_useOptimistic์ ํ์ ํ์ฉํ ์ ์์ต๋๋ค.